import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

public class OpenApiDemo {

    public static void main(String[] args) {
        System.out.println(post("{\"b-field5\":200,\"a-field2\":\"i-m-k\"}"));
    }

    private final static String APP_ID = "10000001110200120312";
    private final static String APP_SECRET = "yo5dowO3xkWcI3Yrc5D3s";
    private final static String URL = "http://127.0.0.1:9527/user/user/app-context";

    public static String post(String json) throws IllegalStateException {
        HttpResponse result = null;
        try {
            Long _t = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
            Map<String, Object> innerMap = JSON.parseObject(json).getInnerMap();
            String sign = signMap(innerMap, APP_SECRET, _t);
            result = HttpUtil.createPost(URL)
                    .header("Content-Type", "application/json")
                    .header("app-id", APP_ID)
                    .header("api-sign", sign)
                    .header("api-time-stamp", String.valueOf(_t))
                    .body(json)
                    .execute();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (result != null && HttpStatus.HTTP_OK == result.getStatus()) {
            return result.body();
        }
        throw new IllegalStateException("请求失败!");
    }

    /**
     * 对对象进行签名
     *
     * @param obj
     * @param signKey
     * @return
     * @throws IllegalAccessException
     */
    public static String signObj(Object obj, String signKey, Long _t) throws IllegalAccessException {
        Map<String, Object> map = dtoToMap(obj);
        return signMap(map, signKey, _t);
    }

    /**
     * 对Map进行签名
     *
     * @param map
     * @param signKey
     * @param _t
     * @return
     */
    public static String signMap(Map<String, Object> map, String signKey, Long _t) {
        String signStr = toQuery(map) + "&key=" + signKey + "&_t=" + _t;
        return md5Digest(signStr);
    }

    private static Map<String, Object> dtoToMap(Object object) throws IllegalAccessException {
        Map<String, Object> params = new HashMap<>(16);
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String name = field.getName();
            Object obj = field.get(object);
            if (obj != null) {
                params.put(name, obj);
            }
        }
        return params;
    }

    private static String toQuery(Map<String, Object> map) {
        Map<String, Object> params = new TreeMap<String, Object>(map);
        String reString = "";
        Iterator it = params.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry) it.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            reString = reString + key + "=" + value + "&";
        }
        if ("" == reString) {
            return reString;
        }
        reString = reString.substring(0, reString.length() - 1);
        return reString;
    }

    private static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static final String md5Digest(String res) {
        if (res == null || "".equals(res)) {
            return null;
        }
        byte[] strTemp = res.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(strTemp);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf];
                str[k++] = HEX_DIGITS[byte0 & 0xf];
            }
            String dd = new String(str);
            return dd;
        } catch (Exception e) {
            return null;
        }
    }
}
